package com.kexilo.exception.deadletter;

import com.kexilo.exception.domain.ExceptionRecord;
import com.kexilo.exception.service.ExceptionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 死信队列
 * 用于处理严重异常和失败的消息
 * 
 * @author Kexilo
 */
@Component
public class DeadLetterQueue {
    
    private static final Logger log = LoggerFactory.getLogger(DeadLetterQueue.class);
    
    /**
     * 内存中的死信消息队列
     */
    private final ConcurrentLinkedQueue<DeadLetterMessage> deadLetterMessages = new ConcurrentLinkedQueue<>();
    
    /**
     * 死信消息计数器
     */
    private final AtomicLong messageCounter = new AtomicLong(0);
    
    /**
     * 最大队列大小
     */
    private static final int MAX_QUEUE_SIZE = 10000;
    
    @Autowired(required = false)
    private ExceptionService exceptionService;
    
    /**
     * 发送消息到死信队列
     * 
     * @param requestUri 请求URI
     * @param exception 异常对象
     * @param source 异常来源
     */
    @Async
    public void sendToDeadLetter(String requestUri, Exception exception, String source) {
        sendToDeadLetter(requestUri, exception, source, null);
    }
    
    /**
     * 发送消息到死信队列（带额外信息）
     * 
     * @param requestUri 请求URI
     * @param exception 异常对象
     * @param source 异常来源
     * @param additionalInfo 额外信息
     */
    @Async
    public void sendToDeadLetter(String requestUri, Exception exception, String source, String additionalInfo) {
        try {
            long messageId = messageCounter.incrementAndGet();
            
            // 创建死信消息
            DeadLetterMessage message = new DeadLetterMessage();
            message.setMessageId(String.valueOf(messageId));
            message.setRequestUri(requestUri);
            message.setSource(source);
            message.setException(exception);
            message.setAdditionalInfo(additionalInfo);
            message.setCreateTime(LocalDateTime.now());
            message.setProcessed(false);
            
            // 添加到队列
            addToQueue(message);
            
            // 记录异常到异常服务
            recordToExceptionService(message);
            
            log.warn("消息已发送到死信队列: [{}] {} - {}", messageId, source, exception.getMessage());
            
        } catch (Exception e) {
            log.error("发送死信消息失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 添加消息到队列
     * 
     * @param message 死信消息
     */
    private void addToQueue(DeadLetterMessage message) {
        // 检查队列大小，防止内存溢出
        if (deadLetterMessages.size() >= MAX_QUEUE_SIZE) {
            // 移除最旧的消息
            DeadLetterMessage oldestMessage = deadLetterMessages.poll();
            if (oldestMessage != null) {
                log.warn("死信队列已满，移除最旧消息: {}", oldestMessage.getMessageId());
            }
        }
        
        deadLetterMessages.offer(message);
    }
    
    /**
     * 记录到异常服务
     * 
     * @param message 死信消息
     */
    private void recordToExceptionService(DeadLetterMessage message) {
        try {
            if (exceptionService != null && message.getException() != null) {
                ExceptionRecord record = convertToExceptionRecord(message);
                exceptionService.recordException(record);
            }
        } catch (Exception e) {
            log.error("记录死信消息到异常服务失败: {}", e.getMessage());
        }
    }
    
    /**
     * 转换死信消息为异常记录
     * 
     * @param message 死信消息
     * @return 异常记录
     */
    private ExceptionRecord convertToExceptionRecord(DeadLetterMessage message) {
        ExceptionRecord record = new ExceptionRecord();
        
        record.setExceptionId("DLQ_" + message.getMessageId());
        record.setExceptionType(message.getException().getClass().getSimpleName());
        record.setExceptionMessage(message.getException().getMessage());
        record.setSource("DeadLetter:" + message.getSource());
        record.setOccurTime(message.getCreateTime());
        record.setRequestUrl(message.getRequestUri());
        record.setLevel("ERROR"); // 死信消息都是高优先级
        record.setStatus("DEAD_LETTER");
        
        if (message.getAdditionalInfo() != null) {
            record.setRemark("Additional Info: " + message.getAdditionalInfo());
        }
        
        return record;
    }
    
    /**
     * 获取队列中的消息数量
     * 
     * @return 消息数量
     */
    public int getQueueSize() {
        return deadLetterMessages.size();
    }
    
    /**
     * 获取死信消息总数
     * 
     * @return 消息总数
     */
    public long getTotalMessageCount() {
        return messageCounter.get();
    }
    
    /**
     * 获取未处理的死信消息
     * 
     * @return 未处理消息列表
     */
    public java.util.List<DeadLetterMessage> getUnprocessedMessages() {
        return deadLetterMessages.stream()
            .filter(msg -> !msg.isProcessed())
            .collect(java.util.stream.Collectors.toList());
    }
    
    /**
     * 标记消息为已处理
     * 
     * @param messageId 消息ID
     * @return 是否标记成功
     */
    public boolean markAsProcessed(String messageId) {
        for (DeadLetterMessage message : deadLetterMessages) {
            if (messageId.equals(message.getMessageId())) {
                message.setProcessed(true);
                message.setProcessTime(LocalDateTime.now());
                log.info("死信消息已标记为已处理: {}", messageId);
                return true;
            }
        }
        return false;
    }
    
    /**
     * 清理已处理的消息
     * 
     * @return 清理的消息数量
     */
    public int cleanupProcessedMessages() {
        int cleanedCount = 0;
        DeadLetterMessage message;
        while ((message = deadLetterMessages.peek()) != null && message.isProcessed()) {
            deadLetterMessages.poll();
            cleanedCount++;
        }
        
        if (cleanedCount > 0) {
            log.info("已清理 {} 条已处理的死信消息", cleanedCount);
        }
        
        return cleanedCount;
    }
    
    /**
     * 重置队列
     */
    public void resetQueue() {
        deadLetterMessages.clear();
        messageCounter.set(0);
        log.info("死信队列已重置");
    }
    
    /**
     * 检查死信队列是否可用
     * 
     * @return 是否可用
     */
    public boolean isAvailable() {
        return true; // 死信队列总是可用的
    }
    
    /**
     * 死信消息内部类
     */
    public static class DeadLetterMessage {
        private String messageId;
        private String requestUri;
        private String source;
        private Exception exception;
        private String additionalInfo;
        private LocalDateTime createTime;
        private LocalDateTime processTime;
        private boolean processed;
        
        // Getters and Setters
        public String getMessageId() { return messageId; }
        public void setMessageId(String messageId) { this.messageId = messageId; }
        
        public String getRequestUri() { return requestUri; }
        public void setRequestUri(String requestUri) { this.requestUri = requestUri; }
        
        public String getSource() { return source; }
        public void setSource(String source) { this.source = source; }
        
        public Exception getException() { return exception; }
        public void setException(Exception exception) { this.exception = exception; }
        
        public String getAdditionalInfo() { return additionalInfo; }
        public void setAdditionalInfo(String additionalInfo) { this.additionalInfo = additionalInfo; }
        
        public LocalDateTime getCreateTime() { return createTime; }
        public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
        
        public LocalDateTime getProcessTime() { return processTime; }
        public void setProcessTime(LocalDateTime processTime) { this.processTime = processTime; }
        
        public boolean isProcessed() { return processed; }
        public void setProcessed(boolean processed) { this.processed = processed; }
    }
}
